package auth

import (
	"admin/dto"
	m "admin/models/auth"
	"admin/utils/pagination"
	"github.com/gin-gonic/gin"
	"gitlab.jkluck.vip/casino/golang/ca-common-util/library/log"
	"go.uber.org/zap"
	"time"

	"gorm.io/gorm"
)

// RoleRepoInterface 角色仓库接口
type RoleRepoInterface interface {
	List(ctx *gin.Context, req dto.RoleListDto) (*pagination.PageResult[m.Role], error)
	Create(ctx *gin.Context, role *m.Role) error
	Update(ctx *gin.Context, role *m.Role) error
	Delete(ctx *gin.Context, id int64) error
	GetByID(ctx *gin.Context, id int64) (*m.Role, error)
	GetRoleByName(ctx *gin.Context, name string) (*m.Role, error)
}

// RoleRepo 基于GORM的角色仓库实现
type RoleRepo struct{ db *gorm.DB }

// NewGormRoleRepository 创建基于GORM的角色仓库实例
// db: GORM数据库连接
// 返回值: 角色仓库实例指针
func NewRoleRepo(db *gorm.DB) *RoleRepo {
	return &RoleRepo{
		db: db,
	}
}

// List 获取角色列表
// 返回值: 角色列表和错误信息
func (r *RoleRepo) List(ctx *gin.Context, req dto.RoleListDto) (*pagination.PageResult[m.Role], error) {
	db := r.db.Model(&m.Role{})
	if req.Keyword != "" {
		db = db.Where("name LIKE ? OR description LIKE ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}
	return pagination.Paginate[m.Role](db, req.PageInfo, &[]m.Role{})
}

// Create 创建角色
// role: 角色对象
// 返回值: 错误信息
func (r *RoleRepo) Create(ctx *gin.Context, role *m.Role) error {
	// 事务确保数据一致
	return r.db.Transaction(func(db *gorm.DB) error {
		// 创建角色基础信息
		if err := db.Create(role).Error; err != nil {
			log.InfoCtx(ctx, "创建角色失败", zap.Error(err))
			return err
		}
		//// 如果关联权限
		//if len(role.Permissions) > 0 {
		//	// 批量操作关联数据
		//	rolePermissions := make([]m.RolePermission, len(role.Permissions))
		//	for i, permission := range role.Permissions {
		//		rolePermissions[i] = m.RolePermission{
		//			RoleID:       role.ID,
		//			PermissionID: permission.ID,
		//		}
		//	}
		//	// 批量保存角色权限关联数据
		//	if err := db.Create(&rolePermissions).Error; err != nil {
		//		return err
		//	}
		//}

		// 处理 角色权限关联表的插入
		if len(role.Permissions) > 0 {
			// 这种方式会自动处理关联表的插入
			if err := db.Model(role).Association("Permissions").Append(role.Permissions); err != nil {
				log.InfoCtx(ctx, "创建角色权限关联数据失败", zap.Error(err))
				return err
			}
		}

		// 处理 角色菜单关联表的插入
		if len(role.Menus) > 0 {
			// 这种方式会自动处理关联表的插入
			if err := db.Model(role).Association("Menus").Append(role.Menus); err != nil {
				log.InfoCtx(ctx, "创建角色菜单关联数据失败", zap.Error(err))
				return err
			}
		}

		return nil
	})
}

// Update 更新角色
// role: 角色对象
// 返回值: 错误信息
func (r *RoleRepo) Update(ctx *gin.Context, role *m.Role) error {
	// 事务确保数据一致
	return r.db.Transaction(func(db *gorm.DB) error {
		// 创建角色基础信息
		if err := db.Model(&m.Role{}).Where("id = ?", role.ID).Updates(map[string]interface{}{
			"name":        role.Name,
			"description": role.Description,
			"updated_at":  time.Now(),
		}).Error; err != nil {
			log.InfoCtx(ctx, "更新角色失败", zap.Error(err))
			return err
		}

		// 处理 角色权限关联表的插入
		if len(role.Permissions) > 0 {
			// 这种方式会自动处理关联表的插入
			if err := db.Model(role).Association("Permissions").Replace(role.Permissions); err != nil {
				log.InfoCtx(ctx, "更新角色权限表失败", zap.Error(err))
				return err
			}
		}

		// 处理 角色菜单关联表的插入
		if len(role.Menus) > 0 {
			// 这种方式会自动处理关联表的插入
			if err := db.Model(role).Association("Menus").Replace(role.Menus); err != nil {
				log.InfoCtx(ctx, "更新角色菜单表失败", zap.Error(err))
				return err
			}
		}

		// 记录关联变化日志

		return nil
	})
}

// Delete 删除角色
// id: 角色ID
// 返回值: 错误信息
func (r *RoleRepo) Delete(ctx *gin.Context, id int64) error {
	// 使用GORM删除指定ID的角色
	return r.db.Transaction(func(db *gorm.DB) error {
		// 删除角色信息
		if err := db.Delete(&m.Role{}, id).Error; err != nil {
			log.InfoCtx(ctx, "删除角色失败", zap.Error(err))
			return err
		}
		// 删除角色权限关联信息
		if err := db.Where("role_id = ?", id).Delete(&m.RolePermission{}).Error; err != nil {
			log.InfoCtx(ctx, "删除角色权限关联信息失败", zap.Error(err))
			return err
		}
		// 删除角色菜单关联信息
		if err := db.Where("role_id = ?", id).Delete(&m.RoleMenu{}).Error; err != nil {
			log.InfoCtx(ctx, "删除角色菜单关联信息失败", zap.Error(err))
			return err
		}
		return nil
	})
}

// GetByID 根据ID获取角色
// id: 角色ID
// 返回值: 角色对象和错误信息
func (r *RoleRepo) GetByID(ctx *gin.Context, id int64) (*m.Role, error) {
	var role m.Role
	// 预加载权限信息并根据ID查询角色
	if err := r.db.Preload("Permissions").First(&role, id).Error; err != nil {
		log.InfoCtx(ctx, "使用 role id获取角色失败", zap.Error(err))
		return nil, err
	}
	return &role, nil
}

// GetRoleByName 根据角色名称获取角色信息
// name: 角色名称
// 返回值: 角色对象和错误信息
func (r *RoleRepo) GetRoleByName(ctx *gin.Context, name string) (*m.Role, error) {
	var role m.Role
	return &role, r.db.Where("name = ?", name).First(&role).Error
}
